package com.cetc;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @Classname DynamicProxyTest
 * @Description 动态代理举例
 * @Date 2022/12/13 20:43
 * @Created by louzhuangxi
 */
public class DynamicProxyTest {

    /**
     * 要想实现动态代理，需要解决的问题：
     * 1.如何根据加载到内存中的被代理类，动态的创建一个代理类及其对象
     * 2.当通过代理类的对象调用方法时，如何动态的去调用被代理类中的同名方法
     */

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //返回的是一个代理类对象，该代理类对象实际上也实现Human中定义的接口
        Human human = (Human) ProxyFactory.getInstance(superMan);
        System.out.println("proxy代理类对象:" + human.getClass());
        human.eat("大米");
        String belief = human.getBelief();
        System.out.println(belief);
    }
}

interface Human {
    /**
     * 获取信仰
     */
    String getBelief();

    /**
     * 吃
     */
    void eat(String food);
}

/**
 * 被代理类
 */
class SuperMan implements Human {

    @Override
    public String getBelief() {
        return "I believe I can fly!!";
    }

    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃：" + food);
    }
}

/**
 * 代理类
 */
class MyInvocationHandler implements InvocationHandler {
    private Object obj;

    public void bind(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //即为代理类要调用的方法，此方法也作为被代理类要调用的方法

        CommonUtil.method01();
        Object invoke = method.invoke(obj, args);
        CommonUtil.method02();
        return invoke;
    }
}

class CommonUtil{
    public static void method01(){
        System.out.println("方法体1");
    }

    public static void method02(){
        System.out.println("方法体2");
    }
}

/**
 * 代理工厂类
 */
class ProxyFactory {
    /**
     * 根据被代理类对象创建代理类
     *
     * @param obj 被代理类对象
     * @return 动态代理对象
     */
    public static Object getInstance(Object obj) {
        System.out.println("被代理类对象:" + obj.getClass());
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
        myInvocationHandler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler);
    }
}